<template>
  <div class="create-post-page">
    <h4>{{ isEditMode ? "编辑文章" : "新建文章" }}</h4>
    <!-- 如果选择了文件，就会触发change事件 -->
    <!-- <input type="file" name="file" @change.prevent="handleFileChange" /> -->
    <!-- file-uploaded为组件emit出来的自定义事件 触发函数为onFileUploaded -->
    <uploader
      action="/upload"
      :beforeUpload="uploadCheck"
      @file-uploaded="handleFileUploaded"
      @file-uploaded-error="onFileUploadedError"
      :uploaded="uploadedData"
      class="d-flex align-items-center justify-content-center bg-light text-secondary w-100 my-4"
    >
      <h2>点击/拖拽上传图片</h2>
      <!-- 这里v-slot简写成# -->
      <template #loading>
        <!-- <div class="d-flex">
          <div class="spinner-border text-secondary" role="status">
            <span class="visually-hidden">Loading...</span>
          </div>
          <h2>正在上传</h2>
        </div> -->
      </template>
      <!-- 数据是在插槽定义的组件中的 而用这个数据的结构是由这个插槽的使用者而决定的 -->
      <!-- 完善作用域props 得到子中的数据 然后在上传成功之后展示图片 -->
      <template #uploaded="dataProps">
        <div class="uploaded-area">
          <img :src="dataProps.uploadedData.data.url" width="500" />
          <h3>点击/拖拽重新上传</h3>
        </div>
      </template>
    </uploader>
    <validate-form @form-submit="onFormSubmit">
      <div class="mb-3">
        <label class="form-label">文章标题：</label>
        <validate-input
          :rules="titleRules"
          v-model="titleVal"
          placeholder="请输入文章标题"
          type="text"
        />
      </div>
      <div class="mb-3">
        <label class="form-label">文章详情：</label>
        <editor
          v-model="contentVal"
          :options="editorOptions"
          @blur="checkEditor"
          ref="editorRef"
          :class="{ 'is-invalid': !editorStatus.isValid }"
        ></editor>
        <span v-if="!editorStatus.isValid" class="invalid-feedback mt1">{{
          editorStatus.message
        }}</span>
        <!-- <validate-input
          rows="10"
          type="text"
          tag="textarea"
          placeholder="请输入文章详情"
          :rules="contentRules"
          v-model="contentVal"
        /> -->
      </div>
      <template #submit>
        <button class="btn btn-primary btn-large">
          {{ isEditMode ? "更新文章" : "发表文章" }}
        </button>
      </template>
    </validate-form>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, ref, reactive } from "vue";
import { useStore } from "vuex";
import { useRouter, useRoute } from "vue-router";
import { GlobalDataProps, PostProps, ResponseType, ImageProps } from "../store";
import ValidateInput, { RulesProp } from "../components/ValidateInput.vue";
import ValidateForm from "../components/ValidateForm.vue";
import axios from "axios";
import EasyMDE, { Options } from "easymde";
import Editor from "../components/Editor.vue";
import Uploader from "@/components/Uploader.vue";
import createMessage from "../components/createMessage";
import { beforeUploadCheck } from "../helper";

// 编辑器实例身上的两个方法
interface EditorInstance {
  clear: () => void;
  getMDEInstance: () => EasyMDE | null;
}

export default defineComponent({
  name: "Login",
  components: {
    ValidateInput,
    ValidateForm,
    Uploader,
    Editor
  },
  setup() {
    const uploadedData = ref();
    const titleVal = ref("");
    // 编辑器的 status
    const editorStatus = reactive({
      isValid: true, // 判断是否通过
      message: ""
    });
    // userouter是定义路由的行为 useroute是定义路由的信息
    const router = useRouter();
    const route = useRoute();
    const isEditMode = !!route.query.id; // 两个!!转换成布尔类型 当传入id的时候表示是编辑状态
    const textArea = ref<null | HTMLTextAreaElement>(null);
    const editorRef = ref<null | EditorInstance>(); // 编辑器组件的ref 其中包含两个实例方法
    const store = useStore<GlobalDataProps>();
    let imageId = "";
    // editorOptions设置为Options类型的 把拼写检查置为false 这样打入中文就不会显示为红色的了
    const editorOptions: Options = {
      spellChecker: false
    };
    const titleRules: RulesProp = [
      { type: "required", message: "文章标题不能为空" }
    ];
    const contentVal = ref("");
    // const contentRules: RulesProp = [
    //   { type: "required", message: "文章详情不能为空" }
    // ];
    // 检查editor的内容 当提交的时候或者blur的时候触发
    const checkEditor = () => {
      if (contentVal.value.trim() === "") {
        editorStatus.isValid = false;
        editorStatus.message = "文章详情不能为空！";
      } else {
        editorStatus.isValid = true;
        editorStatus.message = "";
      }
    };
    onMounted(() => {
      if (editorRef.value) {
        editorRef.value.getMDEInstance();
        // console.log(editorRef.value.getMDEInstance()); // 测试实例方法
      }
      if (isEditMode) {
        // 调用接口请求文章 记得使用interface ResponseType 并传入泛型<PostProps> （在使用的时候再指定类型的一种特性）
        store
          .dispatch("fetchPost", route.query.id)
          .then((rawData: ResponseType<PostProps>) => {
            const currentPost = rawData.data;
            if (currentPost.image) {
              uploadedData.value = { data: currentPost.image };
            }
            titleVal.value = currentPost.title;
            contentVal.value = currentPost.content || "";
          });
      }
    });
    const handleFileUploaded = (rawData: ResponseType<ImageProps>) => {
      // 拿到post请求返回的image的id
      if (rawData.data._id) {
        imageId = rawData.data._id;
      }
    };
    const onFormSubmit = (result: boolean) => {
      checkEditor(); // 提交表单的时候也要触发检查函数
      if (result && editorStatus.isValid) {
        const { column, _id } = store.state.user;
        if (column) {
          const newPost: PostProps = {
            title: titleVal.value,
            content: contentVal.value,
            column,
            author: _id
          };
          // 如果是编辑模式的话就是updatePost 如果是新建文章就是createPost
          const actionName = isEditMode ? "updatePost" : "createPost";
          const sendData = isEditMode
            ? {
                id: route.query.id,
                payload: newPost
              }
            : newPost;
          // 此时 如果有imageId 上传过文件
          if (imageId) {
            newPost.image = imageId;
          }
          store.dispatch(actionName, sendData).then(() => {
            // createMessage(
            //   "文章发表成功，2秒后即将跳转至列表页",
            //   "success",
            //   2000
            // );
            createMessage("文章发表成功", "success", 2000, "即将跳转至列表页");
            setTimeout(() => {
              // console.log(column);
              router.push({ name: "column", params: { id: column } });
            }, 2000);
          });
          // store.commit("createPost", newPost);
        }
      }
    };
    // 新增上传文件
    const handleFileChange = (e: Event) => {
      const target = e.target as HTMLInputElement; // 断言成html输入框属性就能拿到input的一些属性了
      const files = target.files; // file这里是一个对象 而不是数组 const files: FileList | null
      if (files) {
        // 只选择上传的第一个文件
        const uploadedFile = files[0];
        const formData = new FormData();
        formData.append(uploadedFile.name, uploadedFile);
        axios
          .post("/upload", formData, {
            // 因为上传文件所以需要设置headers
            headers: { "Content-Type": "multipart/form-data" }
          })
          .then((res: any) => {
            console.log(res);
          });
      }
    };
    // 自定义检查上传文件的函数
    /*const beforeUpload = (file: File) => {
      const isJPG = file.type === "image/jpeg";
      console.log(file.type);
      if (!isJPG) {
        createMessage("上传图片格式只支持jpg", "error");
      }
      return isJPG;
    };*/
    const uploadCheck = (file: File) => {
      const result = beforeUploadCheck(file, {
        format: ["image/jpeg", "image/png"],
        size: 1
      });
      const { passed, error } = result;
      if (error === "format") {
        createMessage("上传文件格式只支持jpg,png！", "error", 2000, "关闭");
      }
      if (error === "size") {
        createMessage("上传文件大小不能超过1kb", "error", 2000, "关闭");
      }
      return passed;
    };
    /*
    // 获取Uploader发送的事件 此时传入的参数rawData是固定格式的
    const onFileUploaded = (rawData: ResponseType<ImageProps>) => {
      if (rawData.code === 0) {
        // rawData.data._id 此处的.xxx都是ImageProps中的 可见泛型的强大之处
        createMessage(`上传成功啦！图片id为${rawData.data._id}`, "success");
      }
    };*/
    // 获取Uploader发送的事件 此时传入的参数rawData是固定格式的
    const onFileUploadedError = (rawData: ResponseType<ImageProps>) => {
      if (rawData.code !== 0) {
        // rawData.data._id 此处的.xxx都是ImageProps中的 可见泛型的强大之处
        createMessage("上传失败", "error");
      }
    };
    return {
      titleRules,
      titleVal,
      contentVal,
      // contentRules,
      checkEditor,
      onFormSubmit,
      handleFileChange,
      uploadCheck,
      // onFileUploaded,
      onFileUploadedError,
      handleFileUploaded,
      uploadedData,
      isEditMode,
      textArea,
      editorOptions,
      editorRef,
      editorStatus
    };
  }
});
</script>
<style lang="css">
.create-post-page .file-upload-container {
  height: 200px;
  cursor: pointer;
  overflow: hidden;
}
.create-post-page .file-upload-container img {
  width: 100%;
  height: 100%;
  /* object-fit 属性指定元素的内容应该如何去适应指定容器的高度与宽度。
    object-fit 一般用于 img 和 video 标签，一般可以对这些元素进行保留原始比例的剪切、缩放或者直接进行拉伸等。 cover 保持原有尺寸比例。但部分内容可能被剪切。*/
  object-fit: cover;
}
.uploaded-area {
  position: relative;
}
.uploaded-area:hover h3 {
  display: block;
}
.uploaded-area h3 {
  display: none;
  position: absolute;
  color: #999;
  text-align: center;
  width: 100%;
  top: 50%;
}
</style>
